using System;
using System.Collections.Generic;
using System.Text;
using NUnit.Framework;

namespace TestUtil.Equality
{
    /// <summary>
    /// Helps with testing that equality for class <typeparamref name="TUnderTest"/> is symmetric, so that if a==b then b==a.
    /// </summary>
    /// <remarks>
    /// <para>
    /// Good discussions of equality include http://codebetter.com/blogs/david.hayden/archive/2005/02/22/51364.aspx and
    /// http://www.codeproject.com/dotnet/DotNetEquality.asp.
    /// </para>
    /// </remarks>
    public sealed class SymmetricEqualityTestHelper<TUnderTest> where TUnderTest : class
    {
        #region Fields

        private CreateTestObjectCallback<TUnderTest> _firstCallback;
        private CreateTestObjectCallback<TUnderTest> _secondCallback;

        #endregion

        #region Constructor

        /// <summary>
        /// Helps with testing symmetric equality.
        /// </summary>
        public SymmetricEqualityTestHelper(CreateTestObjectCallback<TUnderTest> firstCallback, 
                                           CreateTestObjectCallback<TUnderTest> secondCallback)
        {
            _firstCallback = firstCallback;
            _secondCallback = secondCallback;
        }

        #endregion

        # region Public Methods

        /// <summary>
        /// Asserts that symmetric equality rules are adhered to by type <typeparamref name="TUnderTest"/>.
        /// </summary>
        public void PerformTest()
        {
            TUnderTest firstTestObject = _firstCallback();
            TUnderTest secondTestObject = _secondCallback();

            AssertSymmetricEqualityWorks(firstTestObject, secondTestObject);
        }

        # endregion

        #region Support Methods

        private static void AssertSymmetricEqualityWorks(TUnderTest firstTestObject, TUnderTest secondTestObject)
        {
            bool firstEqualsSecond = (firstTestObject == secondTestObject);
            bool secondEqualsFirst = (secondTestObject == firstTestObject);

            Assert.AreEqual(firstEqualsSecond, secondEqualsFirst, "If the first equals the second then the second should equal the first.");
        }

        #endregion
    }
}
